using Admin.NET.Application.Entity;
using Admin.NET.Core;
using Furion.DependencyInjection;
using Microsoft.AspNetCore.Authorization;
using SqlSugar;

namespace Admin.NET.Application.Service.Report;

/// <summary>
/// 库存分布报表（按仓库统计当前库存数量与金额）
/// </summary>
[ApiDescriptionSettings("Report", Name = "inventoryDistribution", Order = 904)]
[Route("api/report/inventoryDistribution")]
[AllowAnonymous]
public class InventoryDistributionReportService : IDynamicApiController, ITransient
{
	private readonly ISqlSugarClient _sqlSugarClient;

	public InventoryDistributionReportService(ISqlSugarClient sqlSugarClient)
	{
		_sqlSugarClient = sqlSugarClient;
	}

	/// <summary>
	/// 分页查询库存分布列表（仓库名称、库存数量、库存金额）
	/// </summary>
	[HttpPost("page")]
	public async Task<object> Page([FromBody] GetInventoryDistributionInput input)
	{
		DateTime? start = input.StartTime?.Date;
		DateTime? end = input.EndTime?.Date;
		if (end != null) end = end.Value.AddDays(1).AddTicks(-1);

		// 分别聚合后在内存合并，避免匿名类型 Join 触发泛型约束错误
		var inboundList = await _sqlSugarClient.Queryable<Sysinstockorder>()
			.WhereIF(start != null, x => x.InDate >= start)
			.WhereIF(end != null, x => x.InDate <= end)
			.WhereIF(!string.IsNullOrWhiteSpace(input.GoodsOrCategory), x => x.GoodsName!.Contains(input.GoodsOrCategory!))
			.GroupBy(x => x.WarehouseName)
			.Select(x => new WarehouseAgg { WarehouseName = x.WarehouseName, Qty = SqlFunc.AggregateSum(x.InQuantity), Amt = SqlFunc.AggregateSum(x.WarehouseAmount) })
			.ToListAsync();

		var outboundList = await _sqlSugarClient.Queryable<Sysoutstockorder>()
			.WhereIF(start != null, x => x.OutDate >= start)
			.WhereIF(end != null, x => x.OutDate <= end)
			.WhereIF(!string.IsNullOrWhiteSpace(input.GoodsOrCategory), x => x.GoodsName!.Contains(input.GoodsOrCategory!))
			.GroupBy(x => x.WarehouseName)
			.Select(x => new WarehouseAgg { WarehouseName = x.WarehouseName, Qty = SqlFunc.AggregateSum(x.OutQuantity), Amt = SqlFunc.AggregateSum(x.OutbouAmount) })
			.ToListAsync();

		var dict = inboundList.ToDictionary(k => k.WarehouseName ?? string.Empty, v => new InventoryDistributionRow
		{
			WarehouseName = v.WarehouseName,
			Quantity = v.Qty,
			Amount = v.Amt
		});

		foreach (var o in outboundList)
		{
			var key = o.WarehouseName ?? string.Empty;
			if (!dict.ContainsKey(key))
			{
				dict[key] = new InventoryDistributionRow { WarehouseName = o.WarehouseName, Quantity = 0, Amount = 0 };
			}
			dict[key].Quantity -= o.Qty;
			dict[key].Amount -= o.Amt;
		}

		var merged = dict.Values.OrderByDescending(x => x.Quantity).ToList();
		var total = merged.Count;
		var paged = merged.Skip((input.Page - 1) * input.PageSize).Take(input.PageSize).ToList();

		return new { result = new { items = paged, total, page = input.Page, pageSize = input.PageSize } };
	}

	/// <summary>
	/// 获取图表数据（x轴仓库，柱状为数量，折线为金额）
	/// </summary>
	[HttpPost("chart")]
	public async Task<object> Chart([FromBody] GetInventoryDistributionInput input)
	{
		DateTime? start = input.StartTime?.Date;
		DateTime? end = input.EndTime?.Date;
		if (end != null) end = end.Value.AddDays(1).AddTicks(-1);

		var inboundList = await _sqlSugarClient.Queryable<Sysinstockorder>()
			.WhereIF(start != null, x => x.InDate >= start)
			.WhereIF(end != null, x => x.InDate <= end)
			.WhereIF(!string.IsNullOrWhiteSpace(input.GoodsOrCategory), x => x.GoodsName!.Contains(input.GoodsOrCategory!))
			.GroupBy(x => x.WarehouseName)
			.Select(x => new WarehouseAgg { WarehouseName = x.WarehouseName, Qty = SqlFunc.AggregateSum(x.InQuantity), Amt = SqlFunc.AggregateSum(x.WarehouseAmount) })
			.ToListAsync();

		var outboundList = await _sqlSugarClient.Queryable<Sysoutstockorder>()
			.WhereIF(start != null, x => x.OutDate >= start)
			.WhereIF(end != null, x => x.OutDate <= end)
			.WhereIF(!string.IsNullOrWhiteSpace(input.GoodsOrCategory), x => x.GoodsName!.Contains(input.GoodsOrCategory!))
			.GroupBy(x => x.WarehouseName)
			.Select(x => new WarehouseAgg { WarehouseName = x.WarehouseName, Qty = SqlFunc.AggregateSum(x.OutQuantity), Amt = SqlFunc.AggregateSum(x.OutbouAmount) })
			.ToListAsync();

		var dict = inboundList.ToDictionary(k => k.WarehouseName ?? string.Empty, v => new InventoryDistributionRow
		{
			WarehouseName = v.WarehouseName,
			Quantity = v.Qty,
			Amount = v.Amt
		});
		foreach (var o in outboundList)
		{
			var key = o.WarehouseName ?? string.Empty;
			if (!dict.ContainsKey(key)) dict[key] = new InventoryDistributionRow { WarehouseName = o.WarehouseName, Quantity = 0, Amount = 0 };
			dict[key].Quantity -= o.Qty;
			dict[key].Amount -= o.Amt;
		}

		var merged = dict.Values.OrderByDescending(x => x.Quantity).ToList();
		var x = merged.Select(d => d.WarehouseName ?? "").ToList();
		var quantity = merged.Select(d => d.Quantity).ToList();
		var amount = merged.Select(d => d.Amount).ToList();

		return new { result = new { x, quantity, amount } };
	}
}

public class GetInventoryDistributionInput
{
	public DateTime? StartTime { get; set; }
	public DateTime? EndTime { get; set; }
	public string? GoodsOrCategory { get; set; }
	public int Page { get; set; } = 1;
	public int PageSize { get; set; } = 10;
}

public class InventoryDistributionRow
{
	public string? WarehouseName { get; set; }
	public int Quantity { get; set; }
	public decimal Amount { get; set; }
}

internal class WarehouseAgg
{
    public string? WarehouseName { get; set; }
    public int Qty { get; set; }
    public decimal Amt { get; set; }
}


